//============================================================================================
/**
 * @file	point_ring.c
 * @brief	おしくらまんじゅう:得点リング関連
 * @author	Nozomu Saito
 */
//============================================================================================

#include "point_ring.h"
#include "push_obj_pri.h"

#define FIELD_MAX	(15)

//点数
#define POINT1	(1)
#define POINT2	(2)
#define POINT3	(3)
#define POINT4	(5)

#define LEVEL2_NUM	(5)
#define LEVEL3_NUM	(4)
#define LEVEL4_NUM	(5)
#define LEVEL2_START_IDX	(1)
#define LEVEL3_START_IDX	(6)
#define LEVEL4_START_IDX	(10)

typedef enum {
	RT_NONE,
	RT_56,
	RT_32,
	RT_24,
	RT_16,
}RING_TYPE;

typedef enum {
	CATEGO_LEFT,
	CATEGO_CENTER,
	CATEGO_RIGHT,
	CATEGO_SWITCH,
}FLD_CATEGO;

typedef struct RING_tag
{
	u16 Range;
	u16 Point;
}RING;

typedef struct RING_DATA_tag
{
	RING_TYPE RingType;
	u16 X;
	u16 Y;
}RING_DATA;

typedef struct FIELD_TYPE_tag
{
	RING_DATA RingData[RING_MAX];
}FIELD_TYPE;

typedef struct RING_DATA_PACK_tag
{
	BOOL Valid;
	const RING_DATA	*RingData;
	int FieldType;
	PKTHLN_ACT_PTR	RingActPtr;
}RING_DATA_PACK;

typedef struct POINT_RING_CNT_tag
{
	RING_DATA_PACK RingDataPack[RING_CNT_MAX];
	int Idx;
}POINT_RING_CNT;

static const RING Ring1 = {56, POINT1};
static const RING Ring2 = {32, POINT2};
static const RING Ring3 = {24, POINT3};
static const RING Ring4 = {16, POINT4};
//static const RING Ring5 = {8, 2};

static const RING *RingList[] = {
	&Ring1,&Ring2,&Ring3,&Ring4,
};


static const FIELD_TYPE Field1 = {
	{ {RT_56, 128, 96}, {RT_NONE, 0, 0}, {RT_NONE, 0, 0}, {RT_NONE, 0, 0} },		//1
};
static const FIELD_TYPE Field2 = {
	{ {RT_24, 64, 64}, {RT_32, 144, 104}, {RT_NONE, 0, 0}, {RT_NONE, 0, 0} },		//2
};
static const FIELD_TYPE Field3 = {
	{ {RT_24, 200, 64}, {RT_32, 96, 112}, {RT_NONE, 0, 0}, {RT_NONE, 0, 0} },		//3
};
static const FIELD_TYPE Field4 = {
	{ {RT_24, 128, 56}, {RT_32, 128, 128}, {RT_NONE, 0, 0}, {RT_NONE, 0, 0} },		//4
};
static const FIELD_TYPE Field5 = {
	{ {RT_32, 192, 64}, {RT_24, 136, 56}, {RT_NONE, 0, 0}, {RT_NONE, 0, 0} },		//5
};
static const FIELD_TYPE Field6 = {
	{ {RT_32, 88, 80}, {RT_24, 200, 128}, {RT_NONE, 0, 0}, {RT_NONE, 0, 0} },			//6
};
static const FIELD_TYPE Field7 = {
	{ {RT_32, 64, 64}, {RT_32, 192, 64}, {RT_16, 56, 136}, {RT_NONE, 0, 0} },		//7
};
static const FIELD_TYPE Field8 = {
	{ {RT_32, 72, 96}, {RT_24, 144, 96}, {RT_16, 200, 96}, {RT_NONE, 0, 0} },		//8
};
static const FIELD_TYPE Field9 = {
	{ {RT_32, 192, 64}, {RT_24, 64, 96}, {RT_16, 184, 144}, {RT_NONE, 0, 0} },		//9
};
static const FIELD_TYPE Field10 = {
	{ {RT_24, 144, 56}, {RT_32, 96, 136}, {RT_16, 184, 104}, {RT_NONE, 0, 0} },		//10
};
static const FIELD_TYPE Field11 = {
	{ {RT_16, 208, 48}, {RT_32, 128, 96}, {RT_16, 48, 144}, {RT_NONE, 0, 0} },		//11
};
static const FIELD_TYPE Field12 = {
	{ {RT_16, 128, 56}, {RT_24, 128, 96}, {RT_16, 128, 136}, {RT_NONE, 0, 0} },		//12
};
static const FIELD_TYPE Field13 = {
	{ {RT_16, 200, 48}, {RT_24, 72, 96}, {RT_16, 184, 144}, {RT_NONE, 0, 0} },		//13
};
static const FIELD_TYPE Field14 = {
	{ {RT_16, 104, 48}, {RT_24, 168, 112}, {RT_16, 48, 144}, {RT_NONE, 0, 0} },		//14
};
static const FIELD_TYPE Field15 = {
	{ {RT_16, 48, 48}, {RT_16, 208, 48}, {RT_24, 128, 128}, {RT_NONE, 0, 0} },		//15
};

static const FIELD_TYPE *FieldType[FIELD_MAX] = {
	&Field1,
	&Field2,
	&Field3,
	&Field4,
	&Field5,
	&Field6,
	&Field7,
	&Field8,
	&Field9,
	&Field10,
	&Field11,
	&Field12,
	&Field13,
	&Field14,
	&Field15,
/**
	&Field16,
*/
};

#if 0

//フィールドのカテゴリわけ
static const u8 LeftField[] = {
	2,4,5,
};

static const u8 RightField[] = {
	1,3,8
};

static const u8 CenterField[] = {
	6						//<0はエントリしないようにしておく。0は開始だけ出るリング
};

static const u8 LRField[] = {
	7,
};

static const FLD_CATEGO FldCatego[FIELD_MAX] = {
	CATEGO_CENTER,		//0
	CATEGO_RIGHT,		//1
	CATEGO_LEFT,		//2
	CATEGO_RIGHT,		//3
	CATEGO_LEFT,		//4
	CATEGO_LEFT,		//5
	CATEGO_CENTER,		//6
	CATEGO_SWITCH,		//7
	CATEGO_RIGHT,		//8
/**
	CATEGO_CENTER,		//9
	CATEGO_CENTER,		//10
	CATEGO_CENTER,		//11
	CATEGO_CENTER,		//12
	CATEGO_CENTER,		//13
	CATEGO_CENTER,		//14
*/
};
#endif

static BOOL CheckRingIO(const u16 inX, const u16 inY,
		const u16 inCX, const u16 inCY, const u16 inRange);

//----------------------------------------------------------------------------
/**
 *	@brief	コントローラ初期化
 *
 *	@param	inHeapID		ヒープＩＤ
 *
 *	@return	PT_RING_CNT_PTR		コントロールポインタ
 */
//-----------------------------------------------------------------------------
PT_RING_CNT_PTR PtRing_Init(const int inHeapID)
{
	PT_RING_CNT_PTR cnt_ptr;
	cnt_ptr = sys_AllocMemory(inHeapID, sizeof(POINT_RING_CNT));
	MI_CpuClear8( cnt_ptr, sizeof(POINT_RING_CNT));
	return cnt_ptr;
}

//----------------------------------------------------------------------------
/**
 *	@brief	コントローラ解放
 *
 *	@param	cnt_ptr		コントローラポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
void PtRing_End(PT_RING_CNT_PTR cnt_ptr)
{
	sys_FreeMemoryEz(cnt_ptr);
}

//----------------------------------------------------------------------------
/**
 *	@brief	アクターセット
 *
 *	@param	cnt_ptr		コントローラポインタ
 *	@param	ActCntPtr	アクターコントローラポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
void PtRing_SetRingAct(PT_RING_CNT_PTR cnt_ptr, PKTHLN_CLACT_CNT_PTR ActCntPtr)
{
	CLACT_WORK_PTR act_ptr;
	int i;
	//リング
	for (i=0;i<RING_CNT_MAX;i++){
		cnt_ptr->RingDataPack[i].RingActPtr =
			PkthlnClAct_GetActPtr(ActCntPtr, RES_CODE_PUSH, ACT_CODE_RING);
		act_ptr = PkthlnClAct_GetClActWorkPtr(cnt_ptr->RingDataPack[i].RingActPtr);
		CLACT_ObjModeSet( act_ptr, GX_OAM_MODE_XLU );
		//プライオリティセット
		CLACT_DrawPriorityChg( act_ptr, PRI_RING );
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	次のフィールドタイプを取得
 *
 *	@param	inNowType		現在タイプ
 *	@param	inLevel			レベル
 *
 *	@return	次のタイプ
 */
//-----------------------------------------------------------------------------
u8 PtRing_GetNextFieldType(const u8 inNowType, const FIELD_LEVEL inLevel)
{
	FLD_CATEGO catego, next;
	u8 type;
	u8 level_start_idx;
	u8 level_num;
	u8 now_level;
	u8 base;

	if (inNowType == FIELD_TYPE_NONE){
		return 0;
	}

	//現在のフィールドタイプのレベルを算出
	if ( inNowType < LEVEL2_START_IDX){
		now_level = FIELD_LEVEL1;
	}else if(inNowType < LEVEL3_START_IDX){
		now_level = FIELD_LEVEL2;
	}else if(inNowType < LEVEL4_START_IDX){
		now_level = FIELD_LEVEL3;
	}else{
		now_level = FIELD_LEVEL4;
	}

	//現在レベルで分岐
	if (inLevel == FIELD_LEVEL2){		//レベル2
		level_start_idx = LEVEL2_START_IDX;
		level_num = LEVEL2_NUM;
	}else if(inLevel == FIELD_LEVEL3){	//レベル3
		level_start_idx = LEVEL3_START_IDX;
		level_num = LEVEL3_NUM;
	}else{		//レベル4
		level_start_idx = LEVEL4_START_IDX;
		level_num = LEVEL4_NUM;
	}

	if (inLevel == now_level){
		u8 temp;
		GF_ASSERT(inNowType >=level_start_idx);
		base = inNowType - level_start_idx + 1;
		temp = gf_rand()%(level_num-1) + base;
		temp %= level_num;
		type = temp + level_start_idx;
	}else{
		type = level_start_idx + ( gf_rand()%level_num );
	}

#if 0
	//現在のフィールドタイプのカテゴリを取得
	catego =  FldCatego[inNowType];

	switch(catego){
	case CATEGO_LEFT:
		next = (gf_rand()%3)+CATEGO_CENTER;
		break;
	case CATEGO_RIGHT:
		next = (gf_rand()%2)+CATEGO_LEFT;
		break;
	case CATEGO_CENTER:
		next = (gf_rand()%3)+CATEGO_RIGHT;
		next %= 4;
		break;
	case CATEGO_SWITCH:
		next = CATEGO_CENTER;
		break;
	}

	switch(next){
	case CATEGO_LEFT:
		type = LeftField[gf_rand()%3];
		break;
	case CATEGO_RIGHT:
		type = RightField[gf_rand()%3];
		break;
	case CATEGO_CENTER:
		type = CenterField[0];
		break;
	case CATEGO_SWITCH:
		type = LRField[0];
		break;
	}
#endif
	return type;
}

//----------------------------------------------------------------------------
/**
 *	@brief		ポイント取得
 *
 *	@param	inNowType	現在のフィールドタイプ
 *	@param	inX			X座標
 *	@param	inY			Y座標
 *	@param	*outRingNo	ヒットしたリングナンバー
 *
 *	@return ポイント
 */
//-----------------------------------------------------------------------------
u8 PtRing_GetPoint(const u8 inNowType, const u16 inX, const u16 inY, u8 *outRingNo)
{
	u8 point;
	u8 i;

	if (inNowType == FIELD_TYPE_NONE){
		return 0;
	}

	point = 0;
	//リング内に入っているかを調べる
	for (i=0;i<RING_MAX;i++){
		const RING_DATA *ring_data;
		const RING *ring;
		ring_data = &FieldType[inNowType]->RingData[i];
		if (ring_data->RingType == RT_NONE){
			break;
		}
		ring = RingList[ring_data->RingType-1];

		if ( CheckRingIO( inX, inY, ring_data->X, ring_data->Y, ring->Range ) ){
			point = ring->Point;
			*outRingNo = i;
			break;
		}
	}

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief		リングフィールド展開
 *
 *	@param	cnt_ptr		コントローラポインタ
 *	@param	inType		フィールドタイプ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
void PtRing_MakeField(PT_RING_CNT_PTR cnt_ptr, const u8 inType)
{
	int i;
	const FIELD_TYPE *fld_type;
	fld_type = FieldType[inType];
	for(i=0;i<RING_MAX;i++){
		const RING_DATA *ring;
		ring = &fld_type->RingData[i];
		if (ring->RingType != RT_NONE){
			RING_DATA_PACK *pack;
			//リングデータ作成
			pack = &cnt_ptr->RingDataPack[cnt_ptr->Idx];

			GF_ASSERT(pack->Valid != TRUE);

			pack->Valid = TRUE;
			pack->FieldType = inType;
			pack->RingData = ring;
			{
				VecFx32 vec;
				CLACT_WORK_PTR	act_ptr;
				act_ptr = PkthlnClAct_GetClActWorkPtr(cnt_ptr->RingDataPack[cnt_ptr->Idx].RingActPtr);
				PkthlnClAct_SetActive(cnt_ptr->RingDataPack[cnt_ptr->Idx].RingActPtr, 1, 1);
				CLACT_AnmChg( act_ptr, ring->RingType-1 );
				vec.z = 0;
				vec.x = ring->X*FX32_ONE;
				vec.y = ring->Y*FX32_ONE;
				CLACT_SetMatrix( act_ptr, &vec );
			}
			cnt_ptr->Idx = (cnt_ptr->Idx + 1)%RING_CNT_MAX;
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	データクリア
 *
 *	@param	cnt_ptr		コントローラポインタ
 *	@param	inType	フィールドタイプ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
void PtRing_ClearData(PT_RING_CNT_PTR cnt_ptr, const u8 inType)
{
	int i,j;
	for (i=0;i<RING_CNT_MAX;i++){
		if (cnt_ptr->RingDataPack[i].FieldType == inType){
			cnt_ptr->RingDataPack[i].FieldType = FIELD_TYPE_NONE;
			cnt_ptr->RingDataPack[i].RingData = NULL;
			cnt_ptr->RingDataPack[i].Valid = FALSE;
			//アクターを非アクティブにする
			PkthlnClAct_SetActive(cnt_ptr->RingDataPack[i].RingActPtr, 0, 0);
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	点数をポイントナンバーに変換
 *
 *	@param	inPoint		点数
 *
 *	@return	ポイントナンバー
 */
//-----------------------------------------------------------------------------
u8 PtRing_ChangeToNo(const u8 inPoint)
{
	u8 no = 0;
	switch(inPoint){
	case POINT1:
		no = 1;
		break;
	case POINT2:
		no = 2;
		break;
	case POINT3:
		no = 3;
		break;
	case POINT4:
		no = 4;
		break;
	default:
		GF_ASSERT(0);
	}
	return no;
}

//----------------------------------------------------------------------------
/**
 *	@brief		リング内外判定
 *
 *	@param	inX			X座標
 *	@param	inY			Y座標
 *	@param	inCX		リング中心Ｘ
 *	@param	inCY		リング中心Ｙ
 *	@param	inRange　	リング半径
 *
 *	@return	BOOL		リング内ならTRUE
 */
//-----------------------------------------------------------------------------
static BOOL CheckRingIO(const u16 inX, const u16 inY,
		const u16 inCX, const u16 inCY, const u16 inRange)
{

	VecFx32 vec, c_vec;
	vec.x = inX * FX32_ONE;
	vec.y = inY * FX32_ONE;
	vec.z = 0;
	c_vec.x = inCX * FX32_ONE;
	c_vec.y = inCY * FX32_ONE;
	c_vec.z = 0;

//	OS_Printf("x_y_cx_cy_r=%d,%d,%d,%d,%d\n",inX,inY,inCX,inCY,inRange);

	VEC_Subtract(&vec, &c_vec, &vec);

	if ( inRange*FX32_ONE > VEC_Mag(&vec) ){
		return TRUE;
	}

	return FALSE;

}

//
//----------------------------------------------------------------------------
/**
 *	@brief	フィールドのリング中心と半径のリストを取得
 *
 *	@param	inNowType	フィールドタイプ
 *	@param	*outList	格納バッファ
 *
 *	@return	num		リング数
 */
//-----------------------------------------------------------------------------
int PtRing_GetRingData(const u8 inNowType, RING_PRM *outList)
{
	int i;
	u8 num = 0;
	for (i=0;i<RING_MAX;i++){
		const RING_DATA *ring_data;
		const RING *ring;
		ring_data = &FieldType[inNowType]->RingData[i];
		if (ring_data->RingType == RT_NONE){
			outList[i].Range = 0;
			outList[i].X = 0;
			outList[i].Y = 0;
			continue;
		}
		ring = RingList[ring_data->RingType-1];

		outList[i].Range = ring->Range;
		outList[i].X = ring_data->X;
		outList[i].Y = ring_data->Y;
		num++;
	}

	return num;
}

